#include "tfCTDInfo.h"
#include "NatDebtDataModel.h"
#include "BondFuture.h"
#include <QDateTime>
#include <uam/UserAccountManager.h>
#include <uam/ServerTimeMgr.h>
#include <bondlib/SSCTDTools.h>
#include <qbtools/tools.h>
#include <bondlib/SSVContainer.h>
#include <core/time/date.h>
#include <qbprotocol/include/rdProto.h>
#include <qbtools/message/MessagePoster.h>
#include <msgcenter/TFMsgProcess.h>
#include "tfBondDataCenter.h"
#include <qbmessage/include/message_bond.h>
#include <qbkernel/include/qb_base.h>
#include <msgcenter/BondMsgProcess.h>
#include <qbcalculator/include/SSCalculatorIF.h>
#include <qbcalculator/Calculator.h>
#include "CalcFuncsLibrary.h"
#include <core/strings/string_util.h>
#include <core/time/system_time.h>

CQuoteBoardLoadCTDInfo::CQuoteBoardLoadCTDInfo()
	: m_CTDActive(false),
	  m_validDate(0)
{
	qbmsg::bond::InitDecodeFuncs();
	qbBase::getNetworkService()->RegisterNetworkEventObserver(this);
	connect(&TFBondDataCenter::instance(), &TFBondDataCenter::recvData, this, &CQuoteBoardLoadCTDInfo::onDataResponse);

	m_handler = msgEventDispatcher.appendListener(EVENT_MESSAGE_ARRIVED, [this](const qb::SSAckMsg* msg) {
		if (msg == nullptr)
			return;
		if (msg->m_FuncID == E_FID_QB_BEST_PRICE_REQ || msg->m_FuncID == E_FID_QB_BEST_PRICE_PUSH_V2)
			onDataArrived(*msg);
		});

}

CQuoteBoardLoadCTDInfo::~CQuoteBoardLoadCTDInfo()
{
	msgEventDispatcher.removeListener(EVENT_MESSAGE_ARRIVED, m_handler);
}

void CQuoteBoardLoadCTDInfo::rebuildData()
{
	if (isActive()) {
		initialBroker();
		initialTFData();
		reqActiveBond();
	}
}

void CQuoteBoardLoadCTDInfo::initialBroker()
{
	m_setBroker.clear();
	std::string brokerId;
	const CBrokerList& brokerList = SSUserAccountManager::instance().GetReadonlyBroker();
	const std::vector<int>& sortID = brokerList.GetSortKey();

	for (int i=0; i<(int)sortID.size(); i++){
		for (CBrokerList::BrokerMap::const_iterator itor=brokerList.GetBrokerMap().begin(); itor!=brokerList.GetBrokerMap().end(); ++itor){
			const CBrokerUnit& stUnit = itor->second;
			if (!CBrokerList::IsValidBroker(stUnit.m_brokerID)) {
				continue;
			}
			if ((stUnit.m_enableFlag_BOND||stUnit.m_enableFlag_NCD) && (stUnit.m_brokerID==sortID[i])){
				brokerId += qb::base::string_format("%d|", stUnit.m_brokerID);
				m_setBroker.insert(stUnit.m_brokerID);
				break;
			}
		}
	}
	
	if (SSUserAccountManager::instance().GetCFETS_Permission()){
		brokerId += qb::base::string_format("%d", NEW_DETAIL_CFETS_BROKER);
		m_setBroker.insert(NEW_DETAIL_CFETS_BROKER);
	}
	log_info("QuoteBoardLoadCTDInfo initial broker data:%s", brokerId.c_str());
}

void CQuoteBoardLoadCTDInfo::initialTFData()
{
	m_mapTFInfo.clear();
	CFutureArray& FutureArray = CBondFuture::instance().GetFutureArray();
	std::string strTFId;
	for (std::vector<CFutureInfo>::const_iterator itor = FutureArray.m_data.begin(); itor != FutureArray.m_data.end(); ++itor){
		if (strcmp(itor->m_Is_Tradable, "Y") == 0){
			strTFId = qb::base::string_format("%s", itor->m_TF_ID);
			if (!strTFId.empty()){
				CQuoteBoardSingleCTDInfo& ctdinfo = m_mapTFInfo[strTFId];
				ctdinfo.m_strTFID = strTFId;
				ctdinfo.m_strTFKey = qb::base::string_format("%s", itor->m_TF_Key);
				ctdinfo.m_deliveryDate = itor->m_Delivery_Date;
			}
		}
	}

	log_info("QuoteBoardLoadCTDInfo initial tf data!");
}

void CQuoteBoardLoadCTDInfo::reqActiveBond()
{
	m_activeBond.m_ListFive.clear();
	m_activeBond.m_ListTen.clear();
	m_activeBond.m_ListTwo.clear();

	xNatDebtActiveBondReq_t req;
	FIELDCOPY(req.m_UserId, SSUserAccountManager::instance().GetUserInfo().m_UserId);
	FIELDCOPY(req.m_UserAccount, SSUserAccountManager::instance().GetUserInfo().m_UserAccount);
	qb::SSRequestMsg msg;
	msg.m_pRequest = &req;
	msg.m_FuncID = E_FID_QB_NAT_DEBT_ACTIVE_BOND_REQ;
	MessagePoster poster(&msg, qbmsg::tf::EncodeFunc);
	poster.send(this);
	log_info("QuoteBoardLoadCTDInfo reqActiveBond!");
}

void CQuoteBoardLoadCTDInfo::onRecvSignal(const xMarketSignalInfo_t* signal) {
	xSignalInfo_t* sig = (xSignalInfo_t*)signal;
	if (sig && isActive()) {
		if (strcmp(sig->m_info, "TF_OPEN") == 0 ||
			strcmp(sig->m_info, "MS") == 0 ||
			strcmp(sig->m_info, "CFETS") == 0) {
			checkData(true);
			reGetAllTFData();
		}
	}
}

STDMETHODIMP_(void) CQuoteBoardLoadCTDInfo::OnRecover(THIS_ int32_t connect_id) {
	if (isActive()) {
		checkData(true);
		reGetAllTFData();
	}
}

void CQuoteBoardLoadCTDInfo::reqTFRefBond()
{
	std::vector<std::string> vctReqKey;
	{
		std::map<std::string, CQuoteBoardSingleCTDInfo>::const_iterator itr = m_mapTFInfo.begin();
		for (; itr != m_mapTFInfo.end(); itr++){
			if (!itr->second.m_strTFKey.empty()) {
				vctReqKey.push_back(itr->second.m_strTFKey);
			}
		}
	}

	QBRefBondReq_t req;
	for (size_t nL=0; nL<vctReqKey.size(); nL++){
		FIELDCOPY(req.m_TF_Key, vctReqKey[nL].c_str());
		qb::SSRequestMsg msg;
		msg.m_pRequest = &req;
		msg.m_FuncID = E_FID_QB_TF_REFBOND_REQ;
		MessagePoster poster(&msg, qbmsg::tf::EncodeFunc);
		poster.send(this);
	}
}
 
void CQuoteBoardLoadCTDInfo::dealRecvBond(xNatDebtActiveBondAck_c* ack)
{
	unregisterCurrentXBond();
	if (!ack) return;
	log_info("QUOTE BOARD LOAD CTD_REQ FIVE SIZE : %d TEN SIZE :%d TWO SIZE :%d", ack->m_ListFive.size(), ack->m_ListTen.size(), ack->m_ListTwo.size());
	std::string strTemp;

	QBQuoteQuery_t stReq;  //xbond
	QBBondFundamentalInfoReq_t reqBasic;//基础数据 
	for (int nL = 0; nL < 3; nL++){
		std::list<TW_BOND>& lstSource = nL == 0 ? ack->m_ListTwo : (nL == 1 ? ack->m_ListFive : ack->m_ListTen);
		std::list<TW_BOND>& lstDest = nL == 0 ? m_activeBond.m_ListTwo : (nL == 1 ? m_activeBond.m_ListFive : m_activeBond.m_ListTen);
		for (std::list<TW_BOND>::const_iterator itr = lstSource.begin(); itr != lstSource.end(); itr++){
			lstDest.push_back(*itr);
			strTemp = qb::base::string_format("%s.%s", itr->m_BondKey, itr->m_ListedMarket);
			if (m_currentKey.find(strTemp) == m_currentKey.end()){
				reqBasic.m_List.push_back(*itr);
				stReq.m_Bond.push_back(*itr);
			}
			m_currentKey.insert(strTemp);
			m_mapReqBond[strTemp] = *itr;
			std::map<std::string, CQuoteBoardSingleCTDInfo>::iterator itrInfo = m_mapTFInfo.begin();
			for (; itrInfo != m_mapTFInfo.end(); itrInfo++){
				CQuoteBoardSingleCTDInfo& ctdInfo = itrInfo->second;
				bool bValid = false;
				if (itrInfo->first.find("TS")!=std::string::npos){
					if (nL == 0) bValid = true;
				}
				else if (itrInfo->first.find("TF")!=std::string::npos){
					if (nL == 1) bValid = true;
				}
				else if (itrInfo->first.find("T")!=std::string::npos){
					if (nL == 2) bValid = true;
				}
				if (bValid){
					CQuoteBoardSingleCTDInfo& cInfo = itrInfo->second;
					cInfo.m_setBondFactor[strTemp] = 0.0;
				}
			}
		}
	}
 	if (reqBasic.m_List.size() > 0){
		qb::SSRequestMsg msg;
		msg.m_pRequest = &reqBasic;
		msg.m_FuncID = E_FID_QB_BOND_FUNDAMENTAL_REQ;
		MessagePoster poster(&msg, qbmsg::bond::EncodeFunc);
		poster.send(this);
 	}
 	if (stReq.m_Bond.size() > 0){
		qb::SSRequestMsg msg;
		msg.m_pRequest = &stReq;
		msg.m_FuncID = E_FID_QB_CFETS_XBOND_QUOTE_QUERY;
		MessagePoster poster(&msg, qbmsg::tf::EncodeFunc);
		poster.send();

		PushMsgInfo pmi(E_FID_QB_CFETS_XBOND_QUOTE_PUSH, "", nullptr);
		msg.m_pRequest = &stReq;
		msg.m_FuncID = E_FID_QB_CFETS_XBOND_QUOTE_PUSH;
		registPush(pmi, &msg);
 	}

	{
		SCOPED_LOCK(m_lock)
		m_mapTFBondPrice.clear();
	}

	std::string strCombTFk;
	std::map<std::string, CQuoteBoardSingleCTDInfo>::const_iterator itrTF = m_mapTFInfo.begin();
	for (; itrTF != m_mapTFInfo.end(); itrTF++){
		std::list<TW_BOND> lstLoop;
		if (itrTF->first.find("TS")!=std::string::npos) lstLoop = ack->m_ListTwo;
		else if (itrTF->first.find("TF")!=std::string::npos) lstLoop = ack->m_ListFive;
		else lstLoop = ack->m_ListTen;
		for (std::list<TW_BOND>::const_iterator itr = lstLoop.begin(); itr != lstLoop.end(); itr++){
			std::set<int>::const_iterator itrBrk = m_setBroker.begin();
			for (; itrBrk != m_setBroker.end(); itrBrk++){
				getCombKey(itrTF->first, itr->m_BondKey, *itrBrk, strCombTFk);
				SCOPED_LOCK(m_lock)
				CCTDGetInfo& curInfo = m_mapTFBondPrice[strCombTFk];
				curInfo.m_strBondKey = qb::base::string_format("%s", itr->m_BondKey);
				curInfo.m_strTFID = itrTF->first;
				curInfo.m_nBroker = *itrBrk;
			}
		}
	}
}

void CQuoteBoardLoadCTDInfo::unregisterCurrentXBond()
{
	if (m_mapReqBond.size() <= 0) {
		return;
	}

 	QBQuoteQuery_t stReq;
	for (std::map<std::string, TW_BOND>::const_iterator itr = m_mapReqBond.begin(); itr != m_mapReqBond.end(); ++itr){
		stReq.m_Bond.push_back(itr->second);
	}
	PushMsgInfo pmi(E_FID_QB_CFETS_XBOND_QUOTE_PUSH_CANCEL, "", nullptr);
	qb::SSRequestMsg msg;
	msg.m_pRequest = &stReq;
	msg.m_FuncID = E_FID_QB_CFETS_XBOND_QUOTE_PUSH_CANCEL;
	unRegistPush(pmi, &msg);

 	m_mapReqBond.clear();
}
 
void CQuoteBoardLoadCTDInfo::getCombKey(const std::string& tfId, const std::string& bondkey, int brk, std::string& comb)
{
	comb = qb::base::string_format("Nat%s-Bond%s-Brk%d", tfId.c_str(), bondkey.c_str(), brk);
}

void CQuoteBoardLoadCTDInfo::onDataResponse(int funcId) {
	switch (funcId) {
	case E_FID_QB_TF_CONTACT_INFO_REQ:{
		initialTFData();
		break;
	}
	default:
		break;
	}
}

void CQuoteBoardLoadCTDInfo::onDataArrived(const qb::SSAckMsg& msg) {
	int funcId = msg.m_FuncID;
	if (!isActive()) return;
	switch (funcId) {
	case E_FID_QB_NAT_DEBT_ACTIVE_BOND_REQ: {
		xNatDebtActiveBondAck_c* ret = (xNatDebtActiveBondAck_c*)msg.m_pRet;
		if (!ret) return;
		dealRecvBond(ret);
		if (msg.m_IsReceving == 0) {
			reqTFRefBond();
		}
		break;
	}
	case E_FID_QB_TF_REFBOND_REQ: {//国债期货相关的现券
		xQBRefBondList_c* ret = (xQBRefBondList_c*)msg.m_pRet;
		if (!ret || ret->m_List.size() == 0) return;
		std::string strTFID = "";
		std::map<std::string, CQuoteBoardSingleCTDInfo>::iterator itr = m_mapTFInfo.begin();
		for (; itr != m_mapTFInfo.end(); ++itr) {
			CQuoteBoardSingleCTDInfo& info = itr->second;
			if (info.setTFRefBond(ret)) {
				strTFID = itr->first;
				break;
			}
		}
		if (msg.m_IsReceving == 0) {
			if (!strTFID.empty()) {
				calculateTF();
			}
			notifyChange();
		}
		break;
	}
	case E_FID_QB_HISSPREAD_CONVERT_FACTOR_REQ: {//转换因子
		xConvertFactorsAck_c* ret = (xConvertFactorsAck_c*)msg.m_pRet;
		if (!ret) return;
		bool bSet = false;
		std::map<std::string, CQuoteBoardSingleCTDInfo>::iterator itr = m_mapTFInfo.begin();
		for (; itr != m_mapTFInfo.end(); ++itr) {
			CQuoteBoardSingleCTDInfo& info = itr->second;
			if (info.setFactor(ret)) bSet = true;
		}
		if (bSet) notifyChange();
		break;
	}
	case E_FID_QB_BOND_FUNDAMENTAL_REQ: {//基础数据
		xBondFundamentalInfoList_c* ret = (xBondFundamentalInfoList_c*)msg.m_pRet;
		if (!ret) return;
		std::vector<SSSingleRawBondFundamentalInfo> vct;
		bondFundamentalInfoConvert(*ret, vct);
		CSSCalculator::addBondFundamentalInfo(vct);
		for (std::list<xBondFundamentalInfo_c>::const_iterator itr = ret->m_List.begin();
			itr != ret->m_List.end();  ++itr) {
			m_setFundamentalBond.insert(itr->m_Bond_Key);
		}
		calculateTF();
		notifyChange();
		break;
	}
	case E_FID_QB_TF_PRICE_REQ_V2:
	case E_FID_QB_TF_PRICE_PUSH_V3: {
		xQBTFPriceList_c* ret = (xQBTFPriceList_c*)msg.m_pRet;
		if (!ret) return;
		std::string strTF;
		std::map<std::string, CQuoteBoardSingleCTDInfo>::iterator itrFind;
		std::list<xQBTFPriceUnit_c>::const_iterator itr = ret->m_List.begin();
		for (; itr != ret->m_List.end(); ++itr) {
			strTF = qb::base::string_format("%s", itr->m_InstrumentID);
			itrFind = m_mapTFInfo.find(strTF);
			if (itrFind != m_mapTFInfo.end()) {
				itrFind->second.m_fTFPrice = itr->m_LastPrice;
				itrFind->second.m_fTFYesPrice = itr->m_PreSettlementPrice;
			}
		}
		calculateTF();
		notifyChange();
		break;
	}
	case E_FID_QB_CFETS_XBOND_QUOTE_QUERY:
	case E_FID_QB_CFETS_XBOND_QUOTE_PUSH:
	case E_FID_QB_BEST_PRICE_REQ:
	case E_FID_QB_BEST_PRICE_PUSH_V2: {//推送最优报价
		xQBBestPriceListAck_c* ret = (xQBBestPriceListAck_c*)msg.m_pRet;
		if (!ret) return;
		bool isCurrent = false;
		std::string strKey;
		if (funcId == E_FID_QB_BEST_PRICE_REQ) {
			if (msg.m_IsReceving != 0) break;
			for (std::set<std::string>::const_iterator itr = m_currentKey.begin(); itr != m_currentKey.end(); ++itr) {
				strKey = *itr;
				calculateBondkey(strKey);
				isCurrent = true;
			}
		}
		else {
			for (std::list<xQBBestPriceUnit_c>::const_iterator itr = ret->m_List.begin(); itr != ret->m_List.end(); ++itr) {
				strKey = qb::base::string_format("%s", itr->m_bondkey);
				if (m_currentKey.find(strKey) != m_currentKey.end()) {
					calculateBondkey(strKey);
					isCurrent = true;
				}
			}
		}
		if (isCurrent) notifyChange();
		break;
	}
	default: break;
	}
}

void CQuoteBoardLoadCTDInfo::loadCTDInfo(CCTDGetInfo & ctdinfo, bool needRate)
{
	if (ctdinfo.m_strTFID.empty()){
		log_info("QuoteBoardLoadCTDInfo Load tf is null ");
		return;
	}

	activeCTD();

	CQuoteBoardSingleCTDInfo sctdInfo;
	{
		SCOPED_LOCK(m_lock)
		auto itr = m_mapTFInfo.find(ctdinfo.m_strTFID);
		if (itr == m_mapTFInfo.end()) {
			log_info("QuoteBoardLoadCTDInfo Load tf can't be find :%s size:%d", ctdinfo.m_strTFID.c_str(), m_mapTFInfo.size());
			return;
		}
		sctdInfo = itr->second;
	}
 
	if (!checkData()){
		reGetAllTFData();
		return;
	}

	std::set<std::string> currentTF;
	loadCurrentTF(currentTF);
	if (currentTF.find(ctdinfo.m_strTFID) == currentTF.end()){
		std::set<std::string> TFs;
		TFs.insert(ctdinfo.m_strTFID);
		reqTFPrice(TFs);
		return;
	}

	{
		SCOPED_LOCK(m_lock)
		auto itrPrc = m_mapTFBondPrice.begin();
		for (; itrPrc != m_mapTFBondPrice.end(); itrPrc++) {
			const std::string& tmpTFID = itrPrc->first;
			const CCTDGetInfo& tmpCTDInfo = itrPrc->second;
			if (tmpTFID.find(ctdinfo.m_strTFID) != std::string::npos) {
				if (tmpCTDInfo.m_dbBasicPrc < -998) {
					continue;
				}
				if (ctdinfo.m_dbBasicPrc < -998) {
					ctdinfo = tmpCTDInfo;
				}
				else if (tmpCTDInfo.m_dbBasicPrc < ctdinfo.m_dbBasicPrc) {
					ctdinfo = tmpCTDInfo;
				}
			}
		}
	}
	
	//如果需要利率相关, 计算出期货对应利率以及BP差
	if (needRate && ctdinfo.m_dbBasicPrc > -998.0){
		if (ctdinfo.m_strBondKey.empty()) return;
		std::string strCombKey = ctdinfo.m_strBondKey + ".CIB";
		ctdinfo.m_dbTFYeild = calcutfRate::GetNatRateParam().GetTFRate(ctdinfo.m_strTFID, sctdInfo.m_deliveryDate, strCombKey, ctdinfo.m_fFactor, sctdInfo.m_fTFPrice);
		ctdinfo.m_dbTFPreYeild = calcutfRate::GetNatRateParam().GetTFRate(ctdinfo.m_strTFID, sctdInfo.m_deliveryDate, strCombKey, ctdinfo.m_fFactor, sctdInfo.m_fTFYesPrice);
		ctdinfo.m_dbBP = calcutfRate::GetNatRateParam().GetTFRateBP(ctdinfo.m_strTFID, sctdInfo.m_deliveryDate, strCombKey, ctdinfo.m_fFactor, sctdInfo.m_fTFPrice, sctdInfo.m_fTFYesPrice);
	}
}
 
bool CQuoteBoardLoadCTDInfo::checkData(bool mstReget)
{
	QDateTime dt = QDateTime::fromTime_t(CSSVContainer::GetServerTime());
	int date = dt.date().month()*100 + dt.date().day();

	if (mstReget || m_validDate!=date){
		log_info("QuoteBoardLoadCTDInfo Checkreget data reget:%d from :%d to %d ", mstReget?1:0, m_validDate, date);
		m_validDate = date;
		rebuildData();
		return false;
	}
	return true;
}

void CQuoteBoardLoadCTDInfo::loadCurrentTF(std::set<std::string>& TFs)
{
	TFs.clear();
	for (auto iter=m_mapTFInfo.begin(); iter!=m_mapTFInfo.end(); ++iter) {
		TFs.insert(iter->first);
	}
}

void CQuoteBoardLoadCTDInfo::reGetAllTFData()
{
	std::set<std::string> setTFID;
	loadCurrentTF(setTFID);
	reqTFPrice(setTFID);
}

void CQuoteBoardLoadCTDInfo::reqTFPrice(const std::set<std::string>& TFs)
{
	QBTFPriceReq_t tfReq;
	for (std::set<std::string>::const_iterator itr=TFs.begin(); itr!=TFs.end(); ++itr){
		if (m_mapTFInfo.find(*itr) != m_mapTFInfo.end()){
			xQBTFInstrument_c insru;
			FIELDCOPY(insru.m_InstrumentID, m_mapTFInfo[*itr].m_strTFID.c_str());
			FIELDCOPY(insru.m_TF_Key, m_mapTFInfo[*itr].m_strTFKey.c_str());
			tfReq.m_List.push_back(insru);
		}
	}

	if (!tfReq.m_List.empty()) {
		qb::SSRequestMsg msg;
		msg.m_pRequest = &tfReq;
		msg.m_FuncID = E_FID_QB_TF_PRICE_REQ_V2;
		MessagePoster poster(&msg, qbmsg::tf::EncodeFunc);
		poster.send(this);

		PushMsgInfo pmi(E_FID_QB_TF_PRICE_PUSH_V3, "", nullptr);
		msg.m_pRequest = &tfReq;
		msg.m_FuncID = E_FID_QB_TF_PRICE_PUSH_V3;
		registPush(pmi, &msg, qbmsg::tf::EncodeFunc);
	}
}

void CQuoteBoardLoadCTDInfo::notifyChange()
{
	//emit ctdChanged();
}

void CQuoteBoardLoadCTDInfo::caculateAll()
{
	calculateTF();
}
 
void CQuoteBoardLoadCTDInfo::calculateTF(std::string TF)
{
	SCOPED_LOCK(m_lock)
	std::map<std::string, CCTDGetInfo>::iterator itr = m_mapTFBondPrice.begin();
	for (; itr != m_mapTFBondPrice.end(); ++itr){
		if (TF.empty() || itr->first.find(TF)!=std::string::npos) {
			calculateSingle(itr->second);
		}
	}
}

void CQuoteBoardLoadCTDInfo::calculateBondkey(const std::string& bond)
{
	SCOPED_LOCK(m_lock)
	std::map<std::string, CCTDGetInfo>::iterator itr = m_mapTFBondPrice.begin();
	for (; itr != m_mapTFBondPrice.end(); ++itr){
		if (itr->first.find(bond)!=std::string::npos){
			calculateSingle(itr->second);
		}
	}
}

void CQuoteBoardLoadCTDInfo::calculateSingle(CCTDGetInfo& ctdinfo)
{
	std::map<std::string, CQuoteBoardSingleCTDInfo>::const_iterator itrFind = m_mapTFInfo.find(ctdinfo.m_strTFID);
	if (itrFind == m_mapTFInfo.end()) return;
	REPORT report;
	std::string strBrk = qb::base::string_format("%d", ctdinfo.m_nBroker);
	std::string strCombkey = ctdinfo.m_strBondKey + ".CIB";
	ctdinfo.initialPrice();
	if (ctdinfo.m_nBroker == NEW_DETAIL_CFETS_BROKER){
		CFETSQUOTE quote;
		if (!CBondContainer::instance().GetCFETSQuoteByKey(ctdinfo.m_strBondKey.c_str(), CBondContainer::lmCIB, CCFETSQuote::XBOND, quote)){
			return;
		}
		FIELDCOPY(report.m_askinfo.m_yield_price, quote.m_OfrPriceYield);
		FIELDCOPY(report.m_askinfo.m_sVolume, quote.m_OfrVol);
		FIELDCOPY(report.m_askinfo.m_description, quote.m_OfrCompanyName.c_str());
		FIELDCOPY(report.m_askinfo.m_clean_price, quote.m_OfrPriceClean);
		if (strlen(report.m_askinfo.m_yield_price) > 0 && (atof(report.m_askinfo.m_yield_price) > 0.001 || atof(report.m_askinfo.m_yield_price) < -0.001)){
			FMTBUF(report.m_askinfo.m_price_status, "%d", 1);
		}
		report.m_time = report.m_create_time = quote.m_time;
		FMTBUF(report.m_price_status, "%d", 1);
	}
	else{
		if (!CBondContainer::instance().GetCompanyRepByKey(strCombkey.c_str(), strBrk.c_str(), report)){
			return;
		}
	}
	if (ctdinfo.m_fFactor < 0.01){
		for (std::map<std::string, float>::const_iterator irFac = itrFind->second.m_setBondFactor.begin();
			irFac != itrFind->second.m_setBondFactor.end(); irFac++){
			if (irFac->first == strCombkey){
				ctdinfo.m_fFactor = irFac->second;
				break;
			}
		}
	}
	if (ctdinfo.m_fFactor < 0.01) return;

	const char* cYld = report.m_askinfo.m_yield_price;
	if ((cYld[0] == '\0') || strcmp(cYld, "0") == 0 || strcmp(cYld, "Ofr") == 0 || strcmp(report.m_askinfo.m_price_status, "0") == 0
		|| (atof(cYld) > -0.0001 && atof(cYld) < 0.0001)) return;

	float fPrc = atof(cYld);
	CNatDebtCalParam calParam(ctdinfo.m_fFactor, fPrc, itrFind->second.m_fTFPrice, ctdinfo.m_strBondKey, ctdinfo.m_strTFID);
	calcuFromPrice(calParam, itrFind->second.m_deliveryDate, ctdinfo.m_dbTFYeild);
	ctdinfo.m_dbIRR = calParam.m_dbIRR;
	ctdinfo.m_dbBasicPrc = calParam.m_dbBasicPrc;
}
 
void CQuoteBoardLoadCTDInfo::calcuFromPrice(CNatDebtCalParam& param, int delDate, double& dbTFYtm)
{
	if (m_setFundamentalBond.find(param.m_strBondKey) == m_setFundamentalBond.end()) return;
	qb::base::CTime tm(CSSVContainer::GetServerTime());
	std::string strCleanDay = qb::base::string_format("%4d%02d%02d", tm.GetYear(), tm.GetMonth(), tm.GetDay());
	param.m_dbYTMPrc = NAT_DEBT_ERROR_NUMBER;
	if (param.m_fFactor < 0.001) return;
	unsigned int unDel = delDate;
	CNatDebtCalPrice calData;
	calData.m_Delivery_Date = unDel;
	calData.m_dbTFPrice = param.m_dbTFPrice;
	calData.m_dbBondPrice = param.m_dbPrice;
	calData.m_stBondkey = param.m_strBondKey;

	if (CNatDebtCalCache::GetInstance().GetPrice(calData)){
		param.m_dbCleanPrc = calData.m_dbClean;
		param.m_dbIRR = calData.m_dbIRR;
		param.m_dbBasicPrc = calData.m_dbBsisPrice;
		param.m_dbYTMPrc = calData.m_dbYTM;
		param.m_dbCashPrice = calData.m_dbCashPrice;
		param.m_dbAccruedAmount = calData.m_dbAccruedAmount;
		dbTFYtm = calData.m_dbTFYTM;
		return;
	}
	ssCalculator::SSBasicCalculationPage sbcp, ini_sbcp = CSSCalculator::basicPageInitialize(param.m_strBondKey, strCleanDay);
	double dbDirtyPrice = -999.0;
	if (param.m_dbPrice < 30){
		sbcp = CSSCalculator::ytmToAll(param.m_strBondKey, strCleanDay, ini_sbcp.couponRateSpread_, ini_sbcp.indexRate_, param.m_dbPrice / 100);
		if (!VerifyValidCalculate(sbcp.cleanPrice_, false))	return;
		param.m_dbYTMPrc = param.m_dbPrice;
		param.m_dbCleanPrc = sbcp.cleanPrice_;
		dbDirtyPrice = sbcp.dirtyPrice_;
	}
	else{
		sbcp = CSSCalculator::cleanPriceToAll(param.m_strBondKey, strCleanDay, ini_sbcp.couponRateSpread_, ini_sbcp.indexRate_, param.m_dbPrice);
		if (!VerifyValidCalculate(sbcp.yieldToMaturity_, false)) return;
		param.m_dbYTMPrc = sbcp.yieldToMaturity_ * 100;
		param.m_dbCleanPrc = param.m_dbPrice;
		dbDirtyPrice = sbcp.dirtyPrice_;
	}

	if (1){//期货价格对应利率
		sbcp = CSSCalculator::cleanPriceToAll(param.m_strBondKey, strCleanDay, ini_sbcp.couponRateSpread_, ini_sbcp.indexRate_, param.m_dbTFPrice);
		if (VerifyValidCalculate(sbcp.yieldToMaturity_, false)){
			dbTFYtm = sbcp.yieldToMaturity_ * 100;
		}
	}

	double dbLstPrice = param.m_dbTFPrice;
	if (!param.m_strTFId.empty() && dbLstPrice > 0){
		param.m_dbBasicPrc = param.m_dbCleanPrc - dbLstPrice * param.m_fFactor;
		unDel = getPreWorkDay(unDel);
		char cExpiryDate[12] = { 0 };
#ifdef WIN32
            _itoa(unDel, cExpiryDate, 10);
#else
            sprintf(cExpiryDate, "%d", unDel);
#endif
		double dbTempIrr = CSSCalculator::impliedRepoRate(param.m_strBondKey, strCleanDay, cExpiryDate, dbLstPrice, param.m_fFactor, dbDirtyPrice);
		if (!VerifyValidCalculate(dbTempIrr)) dbTempIrr = NAT_DEBT_ERROR_NUMBER;
		param.m_dbIRR = 100 * dbTempIrr;
	}

	calData.m_dbYTM = param.m_dbYTMPrc;
	calData.m_dbClean = param.m_dbCleanPrc;
	calData.m_dbIRR = param.m_dbIRR;
	calData.m_dbBsisPrice = param.m_dbBasicPrc;
	calData.m_dbTFYTM = dbTFYtm;
	CNatDebtCalCache::GetInstance().AddPrice(calData);
 }

unsigned int CQuoteBoardLoadCTDInfo::getPreWorkDay(unsigned int date)
{
	static std::map<unsigned int, unsigned int> m_stCTDMapPreDay;
	if (m_stCTDMapPreDay.find(date) != m_stCTDMapPreDay.end()) return m_stCTDMapPreDay[date];
	time_t tPre = qb::base::IntDate::IntToTime(date);
	SSCTDTools::GetPreCFFEXTradingDay(tPre);
	unsigned int ret = qb::base::IntDate::timeToInt(tPre);
	m_stCTDMapPreDay[date] = ret;
	return ret;
}

// void CQuoteBoardLoadCTDInfo::CheckWndEmpty()
// {
// 	if (m_mapWnd.size() <= 0){
// 		StopActiveCTD();
// 	}
// }
// 
// void CQuoteBoardLoadCTDInfo::CancelRegisterPrice(HWND hWnd)
// {
// 	if (m_mapWnd.find(hWnd) == m_mapWnd.end()){
// 		log_info("quoteboardload ctd info cancel have a invalid hwnd!");
// 		CheckWndEmpty();
// 		return;
// 	}
// 	std::set<QString> setRemain,setTF = m_mapWnd[hWnd];
// 	m_mapWnd.erase(hWnd);
// 	for (std::map<HWND, std::set<QString>>::const_iterator itrRe = m_mapWnd.begin(); itrRe != m_mapWnd.end(); itrRe++){
// 		const std::set<QString>& setRe = itrRe->second;
// 		for (std::set<QString>::const_iterator itrRe = setRe.begin(); itrRe != setRe.end(); itrRe++){
// 			setRemain.insert(*itrRe);
// 		}
// 	}
// 
// 	QBTFPriceReq_t tfReq;
// 	xQBTFInstrument_c insru;
// 	QString strTemp, strLog = "LOAD CTD INFO cancel register ";
// 	for (std::set<QString>::const_iterator itrLoop = setTF.begin(); itrLoop != setTF.end(); itrLoop++){
// 		strTemp = *itrLoop;
// 		if (setRemain.find(strTemp) == setRemain.end()){
// 			if (m_mapInfo.find(strTemp) != m_mapInfo.end()){
// 				FIELDCOPY(insru.m_InstrumentID, m_mapInfo[strTemp].m_strTFID.toStdString().c_str());
// 				FIELDCOPY(insru.m_TF_Key, m_mapInfo[strTemp].m_strTFKey.toStdString().c_str());
// 				tfReq.m_List.push_back(insru);
// 				strLog += m_mapInfo[strTemp].m_strTFID;
// 			}
// 		}
// 	}
// 	strLog += "\r\n";
// 	CWnd * pWnd = AfxGetMainWnd();
// 	if (!pWnd){
// 		log_info("QuoteBoardLoadCTDInfo Cancel did't find parent!");
// 		CheckWndEmpty();
// 		return;
// 	}
// 
// 	if (tfReq.m_List.size() > 0){
// 		AfxGetBondReceiver().RemoveRegistryDataWnd(pWnd->GetSafeHwnd(), E_FID_QB_TF_PRICE_PUSH_CANCEL_V3, &tfReq);//国债期货行情推送
// 	}
// 	if (m_mapWnd.size() <= 0){
// 		UnRegisterCurrentXBond();
// 	}
// 	CheckWndEmpty();
// }

void CQuoteBoardLoadCTDInfo::clear()
{
	m_validDate = -1;
	m_activeBond.m_ListTwo.clear();
	m_activeBond.m_ListFive.clear();
	m_activeBond.m_ListTen.clear();
	m_currentKey.clear();
	m_mapTFInfo.clear();
	m_setFundamentalBond.clear();

	{
		//SCOPED_LOCK(m_lock)
		m_mapTFBondPrice.clear();
	}
}

void CQuoteBoardLoadCTDInfo::activeCTD()
{
	if (!isActive()){
		m_CTDActive = true;
		rebuildData();
	}
}
 
void CQuoteBoardLoadCTDInfo::stopActiveCTD()
{
	m_CTDActive = false;
	clear();
}

CQuoteBoardLoadCTDInfo& getCTDInfo()
{
	static CQuoteBoardLoadCTDInfo stCTDInfo;
	return stCTDInfo;
}

